﻿using System;
using System.Configuration;
using System.Data.SqlClient;
using System.Web.Configuration;
using CoreLibrary.Service;
using NLog;

namespace CoreLibrary.Sql.Connection {

    public class BaseConnectionProvider : ServiceBase, IConnectionProvider {
        
        protected override void OnStop()   {}
        protected override void OnDestroy(){}
        protected override void OnStart()  {}

        public string ConnectionString { get; set; }
        public string ConnectionName   { get; set; }

        protected override void OnInit() {
            Asserts.NotBlank(ConnectionString, "Connection String must be provided");
        }
        
        public SqlConnection Acquire() {
            return new SqlConnection(ResolveConnectionString());
        }

        public void Release(SqlConnection conn) {
            if (conn == null) {
                return;
            }
            try {
                conn.Close();
            } 
            catch(Exception exception) {
                LogManager.GetCurrentClassLogger().ErrorException("close SqlConnection failed - " + exception.Message,
                    exception
                );
            }
        }

        public void Close() {
        }

        public T ExecuteQuery<T>(ISqlQuery<T> query) {
            return ExecuteCommand(query);
        }

        public T ExecuteScalar<T>(ISqlScalar<T> scalar) {
            return ExecuteCommand(scalar);
        }

        public T ExecuteUpdate<T>(ISqlUpdator<T> updator) {
            return ExecuteCommand(updator);
        }

        private T ExecuteCommand<T,R>(ISqlCommand<T,R> cmd) {
            SqlConnection sqlConnection = null;
            try {
                sqlConnection = Acquire();
                sqlConnection.Open();
                return SQLUtil.ExecuteCommand(sqlConnection, cmd);
            } 
            finally {
                Release(sqlConnection);
            }
        }

        private string ResolveConnectionString() {
            if (string.IsNullOrEmpty(ConnectionString)) {
                lock (this) {
                    if (string.IsNullOrEmpty(ConnectionString)) {
                        if (string.IsNullOrEmpty(ConnectionName)) {
                            throw new ArgumentException("ConnectionName must be provided.");
                        }

                        var setting = WebConfigurationManager.ConnectionStrings[ConnectionName];
                        if (string.IsNullOrEmpty(setting.ConnectionString)) {
                            throw new ConfigurationErrorsException("ConnectionString is not provided in web.config.");
                        }

                        ConnectionString = setting.ConnectionString;
                    }
                }
            }
            return ConnectionString;
        }
    }

}